Testing
Since v0.20.0, the Halo template uses Jest as the default test runner. This guide will provide you with information on how to write and run tests in this template.
#
1. Organize your testsThere are typically two ways to organize your tests. The first approach involves separating your tests from the source code and put them into a dedicated folder(eg: test
).
... ┣ 📂src ┣ 📂tests ┃ ┣ 📂oauth ┃ ┃ ┣ 📂app ┃ ┃ ┃ ┣ 📜create-app.spec.ts ┃ ┃ ┃ ┗ 📜reset-secret.spec.ts ┃ ┃ ┣ 📂auth ┃ ┃ ┃ ┣ 📜authorize.spec.ts ┃ ┃ ┃ ┣ 📂grant-access ┃ ┃ ┃ ┃ ┣ 📜fixture.ts ┃ ┃ ┃ ┃ ┗ 📜grant_access.spec.ts
Second, you can write your tests alongside the related source code.
📂src ┣ 📂oauth ┃ ┣ 📂app ┃ ┃ ┣ 📂create-app ┃ ┃ ┃ ┣ 📜create-app.cmd.ts ┃ ┃ ┃ ┣ 📜create-app.req.ts ┃ ┃ ┃ ┗ 📜create-app.spec.ts ┃ ┃ ┣ 📂reset-secret ┃ ┃ ┃ ┣ 📜reset-secret.cmd.ts ┃ ┃ ┃ ┣ 📜reset-secret.req.ts ┃ ┃ ┃ ┗ 📜reset-secret.spec.ts ┃ ┣ 📂auth ┃ ┃ ┣ 📂authorize ┃ ┃ ┃ ┣ 📜authorize.spec.ts ┃ ┃ ┃ ┣ 📜authorize.qry.ts ┃ ┃ ┃ ┗ 📜... ┃ ┃ ┣ 📂grant-access ┃ ┃ ┃ ┣ 📂__tests__ ┃ ┃ ┃ ┃ ┣ 📜fixture.ts ┃ ┃ ┃ ┃ ┗ 📜grant_access.spec.ts ┃ ┃ ┃ ┣ 📜grant-access.qry.ts ┃ ┃ ┃ ┗ 📜...
note
If you choose the second method, there are a few things you need to know. CellularJS uses Webpack as a bundler. To prevent your tests from being included in the final bundle, please follow these conventions:
- Test file name must end with
.{spec,test}.{ts,js}
. Eg: create-app.spec.ts. - If you need a more complex structure, create a folder named
__tests__
and put all testing-related files into it.
In the Halo template, both methods are used. The first method is used for e2e tests, and the second is used for unit tests.
#
2. Write unit testIf you write unit test for service. You can use ServiceFactory
for resolving service instance.
// my-info.qry.tsimport { Service } from '@cellularjs/net';
@Service({ scope: 'publish' })export class MyInfoQry { constructor( private irq: IRQ, private userRepo: UserRepository, ) { }
handle() { return 'halo'; }}
// my-info.spec.tsimport { Container } from '@cellularjs/di';import { IRS, ServiceFactory } from '@cellularjs/net';import { RegisterCmd } from './my-info.qry';
describe('User:MyInfoQry', () => { test('resolve service', async () => { const myInfoQry = await ServiceFactory.resolve(MyInfoQry, { /** * By default, the value is true. If false, service provider will be ignored. */ includeServiceProvider: true,
/** * By default, the value is true. If false, service proxy will be ignored. */ includeServiceProxy: true,
/** * Temporary providers or request providers */ providers: [ { token: IRQ, useValue: new IRQ({}, {}) }, { token: UserRepository, useValue: mock }, ],
/** * A container that holds shared providers for a cell. * Usually, you don't need to use this container; all providers * can be provided by using the `providers` property above. */ rootContainer: new Container(), });
const irs = await myInfoQry.handle();
expect(myInfoQry).toBeInstanceOf(MyInfoQry); expect(irs).toBeInstanceOf(IRS); // with the help of ServiceFactory, returned data is converted into IRS instance expect(irs.body).toEqual('halo') });});
#
3. Write e2e testThe Halo template has been preconfigured for Supertest and provides you with a global object called testAgent
for testing.
describe('User:SayHelloQry', () => { test('Say hello', async () => { await testAgent.get('/').expect(200); });});
note
Global setup and teardown for e2e tests is located in the test\setup.ts
file. You can add stuff like database cleaning here.
Example:
// test\setup.tsimport { clearNetwork } from '@cellularjs/net';import { destroyAllDataSource } from '@cellularjs/typeorm';import supertest from 'supertest';import { initApp } from '$gateway/http/app';
beforeEach(async () => { global.server = (await initApp()).listen(); global.testAgent = supertest(global.server);});
afterEach(async () => { await destroyAllDataSource(); await clearNetwork(); global.server?.close();});
#
4. Run test#
4.1. Run unit test$ yarn test
or
$ yarn test --coverage
----------------------|---------|----------|---------|---------|-------------------File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s ----------------------|---------|----------|---------|---------|-------------------All files | 5.81 | 0 | 8.33 | 3.84 | $app/http | 0 | 0 | 0 | 0 | app.ts | 0 | 0 | 0 | 0 | 1-36 index.ts | 0 | 100 | 0 | 0 | 1-17 net.ts | 0 | 100 | 0 | 0 | 1-9 routes.ts | 0 | 100 | 0 | 0 | 1-10 $share/common | 0 | 100 | 0 | 0 | common.module.ts | 0 | 100 | 100 | 0 | 1-10 index.ts | 0 | 100 | 0 | 0 | 1 $share/env | 0 | 100 | 100 | 0 | index.ts | 0 | 100 | 100 | 0 | 1-8 $share/express-proxy | 0 | 0 | 0 | 0 | index.ts | 0 | 0 | 0 | 0 | 1-36 user | 0 | 100 | 100 | 0 | index.ts | 0 | 100 | 100 | 0 | 5-13 user/say-hello | 100 | 100 | 100 | 100 | say-hello.qry.ts | 100 | 100 | 100 | 100 | ----------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 totalTests: 1 passed, 1 totalSnapshots: 0 totalTime: 2.488 s, estimated 3 sDone in 3.23s.
#
4.2. Run e2e test$ yarn test:e2e
or
$ yarn test:e2e --coverage
----------------------|---------|----------|---------|---------|-------------------File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s-----------------------|-----------|------------|-----------|-----------|--------------------All files | 78.61 | 69.23 | 90 | 78.61 |$app/http | 59.74 | 75 | 75 | 59.74 |app.ts | 67.56 | 100 | 100 | 67.56 | 25-36index.ts | 0 | 0 | 0 | 0 | 1-19net.ts | 100 | 100 | 100 | 100 |routes.ts | 100 | 100 | 100 | 100 |$share/common | 100 | 100 | 100 | 100 |common.module.ts | 100 | 100 | 100 | 100 |index.ts | 100 | 100 | 100 | 100 |$share/env | 100 | 100 | 100 | 100 |index.ts | 100 | 100 | 100 | 100 |$share/express-proxy | 92.1 | 57.14 | 100 | 92.1 |index.ts | 92.1 | 57.14 | 100 | 92.1 | 23-25user | 100 | 100 | 100 | 100 |index.ts | 100 | 100 | 100 | 100 |user/say-hello | 100 | 100 | 100 | 100 |say-hello.qry.ts | 100 | 100 | 100 | 100 |---------------------- | --------- | ---------- | --------- | --------- | -------------------
Test Suites: 1 passed, 1 totalTests: 1 passed, 1 totalSnapshots: 0 totalTime: 1.689 s, estimated 2 sDone in 2.65s.